clear 
clc

k = 4; % kFold variable determines the number of parts to divide the images to

imagePath = 'training_set'; % using relative path instead of absolute path
data = cell(1, 3);
data{1} = readImages(strcat(imagePath, '\Diamond'));      % Diamond images
data{2} = readImages(strcat(imagePath, '\Line'));             % Line images
data{3} = readImages(strcat(imagePath, '\Ellipse'));          % Ellipse images

accuracy = zeros(k,1);

for kFoldIteration  = 1 : k
    training_output = cell(3, 3);
    % get the first training set and validation set in kFolds
    [train_diamond , valid_diamond]  = kFold(k, data{1}, kFoldIteration);
    [train_line , valid_line]  = kFold(k, data{2}, kFoldIteration);
    [train_ellipse , valid_ellipse]  = kFold(k, data{3}, kFoldIteration);
    
    % training images
    [training_output{1,1}, training_output{1,2}, training_output{1,3} ] = trainData(train_diamond);
    [training_output{2,1}, training_output{2,2}, training_output{2,3} ] = trainData(train_line);
    [training_output{3,1}, training_output{3,2}, training_output{3,3} ] = trainData(train_ellipse);
    
    % plot the features
    plotFeatures(training_output);
    
    % validation part
    validation_matrix = cell(3,3);
    [validation_matrix{1,1}, validation_matrix{1,2}, validation_matrix{1,3} ] = trainData(valid_diamond);
    [validation_matrix{2,1}, validation_matrix{2,2}, validation_matrix{2,3} ] = trainData(valid_line);
    [validation_matrix{3,1}, validation_matrix{3,2}, validation_matrix{3,3} ] = trainData(valid_ellipse);
    
    % classify images
    classes_1 = discriminantClassifier(formatMatrix(training_output), formatMatrix(validation_matrix));
    classes_2 = kNearestNeighborClassifier(formatMatrix(training_output), formatMatrix(validation_matrix));
    classes_3 = naiveBayesClassifier(formatMatrix(training_output), formatMatrix(validation_matrix));
    
    % vote for the best of both classifiers
    classes = votingFunction([classes_1, classes_2 classes_3]);
    
    % get the probability of error
    accuracy(kFoldIteration,1) = getAccuracy(classes);
end

% clear non used memory
clear classes_1 classes_2 classes_3 data imagePath kFoldIteration train_diamond;
clear train_ellipse train_line training_output valid_diamond valid_ellipse valid_line validation_matrix;

% get the accuracy
avg  = sum(accuracy) / k;
disp(strcat('Accuracy = ', num2str(avg), ' %'));